﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.ServiceModel;
using System.Xml;
using System.ServiceModel.Description;
using PServiceBus.Core.Manager;
using PServiceBus.Core.Runtime.Gateway;
using PServiceBus.Core.Runtime;
using PServiceBus.Core.Runtime.Extensions;
using System.Threading;
using PServiceBus.Services.Gateway.Runtime;
using PServiceBus.Services.Gateway.Services;
using System.Reflection.Emit;
using System.Reflection;
using PServiceBus.Gateway.Interfaces;
using Phoenix.ReflectionExtensions;
using PServiceBus.Core.Runtime.Configuration;

namespace PServiceBus.Endpoints.Gateway {
	public partial class GatewayService : ServiceBase {
		private static MessageBusGateway _service = null;

		private static int _servicePort;
		private static string _serviceName;
        private static string _serviceType;
		private static ServiceInfo _serviceInfo = null;
		private static PerfCounter _perfCounter = new PerfCounter();

		public GatewayService() {
			InitializeComponent();
			System.IO.Directory.SetCurrentDirectory(System.AppDomain.CurrentDomain.BaseDirectory);
			ServiceName = _serviceName;
		}

		private static void Configure() {
			PServiceBus.Core.Runtime.SerializationBootstrapper.Configure();
			PServiceBus.EmailTransport.SerializationBootstrapper.Configure();
			PServiceBus.MSSQLTransport.SerializationBootstrapper.Configure();
			PServiceBus.WCF.NetTcpTransport.SerializationBootstrapper.Configure();
			PServiceBus.Transports.SerializationBootstrapper.Configure();
			PServiceBus.Services.Gateway.Runtime.SerializationBootstrapper.Configure();
		}

		protected override void OnStart(string[] args) {
            DynamicBroker.Broker[_serviceType].New();
			var perfSetting = new Dictionary<string, PerformanceCounterType>() { 
			   {"TotalConnectedClients", PerformanceCounterType.NumberOfItems64}
			};
			Parser.Invoke<Action<string, int, PerfCounter, Dictionary<string, PerformanceCounterType>>>("GSAT", il =>
			{
				var ascmk = AppDomain.CurrentDomain.GetAssemblies()
					.FirstOrDefault(x => x.FullName.StartsWith("System.Core"));
				var pfkco = AppDomain.CurrentDomain.GetAssemblies()
				.FirstOrDefault(x => x.FullName.StartsWith("PServiceBus.Core"));
				var cfgco = AppDomain.CurrentDomain.GetAssemblies()
				.FirstOrDefault(x => x.FullName.StartsWith("PServiceBus.Services.Gateway"));
				var vggklol = pfkco.GetType(Parser.ParseString("143jk()(:)(*("));
				var jgk9l = Type.GetType(Parser.ParseString("kf9))(;;);()-0")).MakeGenericType(vggklol);
				var gkc80k = Assembly.GetExecutingAssembly()
					.GetType(Parser.ParseString("%^^_%_$9:)(:::kv^_)5"));
				var gjh9ujJDk = cfgco.GetType(Parser.ParseString("2#ttf:(P))"));
				var ckfkc2 = il.DefineLabel();
				var vkvcdf = il.DefineLabel();
				var fk0kgo = il.DeclareLocal(typeof(string));
				il.Emit(Parser.O("-22-"));
				il.Emit(Parser.O("-13--"), ckfkc2);
				il.Emit(Parser.O("2--"), vggklol.GetProperty(Parser.ParseString("fkd900---130##-!##%$%^")).GetGetMethod());
				il.Emit(OpCodes.Isinst, jgk9l);
				il.Emit(Parser.O("2--"), ascmk.GetType(Parser.ParseString("6-6-43000--###$%)===050")).GetGenericMethod(Parser.ParseString("%%)^)%*888)08l)**("), new[] { jgk9l }).MakeGenericMethod(vggklol));
				il.Emit(Parser.O("-10"), vkvcdf);
				il.MarkLabel(ckfkc2);
				il.Emit(Parser.O("2--"), gkc80k.GetMethod(Parser.ParseString("a1$cdfs"), Parser.BINDING));
				il.Emit(Parser.O("2--"), cfgco.GetType(Parser.ParseString("avc2fd")).GetMethod(Parser.ParseString("d$fdatt-()2"), Parser.BINDING));
				il.Emit(Parser.O("2--"), gkc80k.GetMethod(Parser.ParseString("gr#tgavvc"), Parser.BINDING));
				il.Emit(Parser.O("-8-"), "endpoint://*:{0}");
				il.Emit(OpCodes.Ldarg_1);
				il.Emit(OpCodes.Box, typeof(int));
				il.Emit(Parser.O("2--"), typeof(String).GetMethod("Format", new[] { typeof(string), typeof(object) }));
				il.Emit(Parser.O("-11"), fk0kgo.LocalIndex);
				il.Emit(Parser.O("--12--"), fk0kgo.LocalIndex);
				il.Emit(Parser.O("21.-"), gjh9ujJDk.GetConstructors()[0]);
				il.Emit(Parser.O("7--"), gkc80k.GetField(Parser.ParseString("#25KU_fda5"), Parser.BINDING));
				il.Emit(Parser.O("23.-"));
				il.Emit(OpCodes.Ldarg_1);
				il.Emit(Parser.O("2--"), vggklol.GetMethod(Parser.ParseString("v4f0JLL)OIF*FJuv--")));
				il.Emit(Parser.O("7--"), gkc80k.GetField(Parser.ParseString("v v_vi)_(();l())"), Parser.BINDING));
				il.Emit(OpCodes.Ldarg_2);
				il.Emit(Parser.O("23.-"));
				il.Emit(OpCodes.Ldarg_3);
				il.Emit(Parser.O("3-"), typeof(PerfCounter).GetMethod("Load"));
				il.Emit(OpCodes.Ldarg_2);
				il.Emit(Parser.O("-8-"), Parser.ParseString("v!r0i:)):((f-1#$)"));
				il.Emit(OpCodes.Ldc_I8, 0L);
				il.Emit(Parser.O("3-"), typeof(PerfCounter).GetMethod("SetValue"));
				il.MarkLabel(vkvcdf);
			})(_serviceName, _servicePort, _perfCounter, perfSetting);
		}

		protected override void OnStop() {
			CloseService();
		}

		private static void CloseService() {
			try {
				_perfCounter.SetValue("TotalConnectedClients", 0);
				if (_serviceInfo != null) _serviceInfo.Delete();
				if (_service != null) _service.Dispose();
				_service = null;
			} catch (Exception ex) {
				EventLog.WriteEntry(_serviceName, ex.ToString());
			}
		}

		static void LoadServiceInfo(string id) {
            var service = ConfigurationParser.Process("services.xml")
                    .Select(x => x["service"] as Dictionary<string, object>)
                    .Select(x => x.ToDictionary(kv => kv.Key, kv => kv.Value == null ? string.Empty : kv.Value.ToString()))
                    .First(x => x["id"] == id);
			_serviceName = service["name"];
			_servicePort = Convert.ToInt32(service["port"]);
            _serviceType = service["type"];
			ShellHelper.NetShAddTCPFirewall(_serviceName, _servicePort);
		}

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		static void Main(string[] args) {
			if (args.Length < 1) 
				throw new ArgumentException("Gateway Service Require service name to be passed to the command line");
			LoadServiceInfo(String.Join(" ", args));
			ServiceBase[] ServicesToRun;
			ServicesToRun = new ServiceBase[] 
			{ 
				new GatewayService() 
			};
			ServiceBase.Run(ServicesToRun);
		}
	}
}